Matterport SDK の Observables を利用してカメラの操作をサブスクライブする
こんにちは、CX事業本部 Delivery部の若槻です。
Matterport の 3D Showcase をWebアプリに埋め込むことができる Matterport SDK for Embeds package では、Observables を介してユーザーが ShowCase を閲覧する際に操作するカメラの状態(カメラポーズ)をサブスクライブすることができます。
Observables をサブスクライブするクラスを「Observer」と言います。Observer がカメラポーズをサブスクライブすることにより、ユーザーが 3D Showcase 上の指定の位置に移動した際に、特定の情報を表示するなどの処理を実装することが可能です。
試してみた
前提
次のエントリの内容を実施済みである前提とします。
サーバーの起動にはWebPackを利用し、コンフィグに環境変数としてMatterportのSDK Keyを記載します。
const HtmlWebpackPlugin = require('html-webpack-plugin'); const path = require('path'); const webpack = require('webpack'); module.exports = { entry: './index.js', output: { path: path.resolve(__dirname, './dist'), filename: 'index_bundle.js', }, plugins: [ new HtmlWebpackPlugin(), new webpack.EnvironmentPlugin({ SDK_KEY: 'SDK_KEY', }), ], };
Functional Observer
カメラの状態(カメラポーズ)は、poseという名前のオブジェクトで表されます。
Functional Observerを利用してposeの状態をサブスクライブするには、次のようにします。
import { setupSdk } from '@matterport/sdk'; const SDK_KEY = process.env.SDK_KEY || ''; const main = async () => { const mpSdk = await setupSdk(SDK_KEY); const poseObserver = (pose) => { console.log(JSON.stringify(pose)); console.log(pose); } mpSdk.Camera.pose.subscribe(poseObserver); }; main().catch((err) => console.error('Error:', err));
npm run dev
を実行してindes.js
をwebpack-dev-serverで起動します。
localhost:8080
にアクセスすると、デモ用のショーケースを表示できました。また、カメラの操作に応じて、コンソールにposeの情報が出力されています。
poseの情報は次のような形式です。3D Showcase 上でのカメラの位置や方向を取得できています。
{ position: { x: -4.11534309387207, y: 1.5915290117263794, z: -1.7111740112304688, }, rotation: { x: -2.3478604260139115, y: 177.69234680289787 }, projection: { 0: 0.7333507537841797, 1: 0, 2: 0, 3: 0, 4: 0, 5: 1.3032253980636597, 6: 0, 7: 0, 8: 0, 9: 0, 10: -1.0000666379928589, 11: -0.2000066637992859, 12: 0, 13: 0, 14: -1, 15: 0, }, sweep: '91800a2940734a2897f806d337440d0d', mode: 'mode.inside', };
Object-Oriented Observer
Object-Oriented Observerを利用してカメラポーズをサブスクライブすることもできます。次のようにonChanged
関数を実装します。
import { setupSdk } from '@matterport/sdk'; const SDK_KEY = process.env.SDK_KEY || ''; const main = async () => { const mpSdk = await setupSdk(SDK_KEY); class PoseObserver { onChanged(pose) { console.log(JSON.stringify(pose)); console.log(pose); } } mpSdk.Camera.pose.subscribe(new PoseObserver()); }; main().catch((err) => console.error('Error:', err));
カメラポーズが取得できています。
Using Multiple Observers
複数の Observer で同時カメラポーズをサブスクライブすることも可能です。
import { setupSdk } from '@matterport/sdk'; const SDK_KEY = process.env.SDK_KEY || ''; const main = async () => { const mpSdk = await setupSdk(SDK_KEY); mpSdk.Camera.pose.subscribe(function (pose) { console.log('pose1'); }); mpSdk.Camera.pose.subscribe({ onChanged(pose) { console.log('pose2'); }, }); }; main().catch((err) => console.error('Error:', err));
同時に2つの Observer で同じカメラの操作から状態を取得できています。
Shutting down an Observer
状態の更新が不要になったら、Observer を Observable から削除する必要があります。Observable をサブスクライブすると、ISubscriptionオブジェクトが返されます。このISubscriptionオブジェクトは、サブスクライブされた Observer を削除し、受信したコールバックを停止するために使用されるオブジェクトです。
import { setupSdk } from '@matterport/sdk'; const SDK_KEY = process.env.SDK_KEY || ''; const main = async () => { const mpSdk = await setupSdk(SDK_KEY); class PoseObserver { onChanged(pose) { console.log(pose); } } const poseSubscription = mpSdk.Camera.pose.subscribe(new PoseObserver()); // 10秒後に Observer をシャットダウン setTimeout(() => { console.log('poseSubscription.cancel()'); poseSubscription.cancel(); }, 10000); }; main().catch((err) => console.error('Error:', err));
アプリの実行から10秒後に Observer をシャットダウンされました。
Cloning an Observer’s View of State
カメラポーズが変更されると Observable が変更されるため、必要に応じて pose の状態を保持する実装を行います。
import { setupSdk } from '@matterport/sdk'; const SDK_KEY = process.env.SDK_KEY || ''; const main = async () => { const mpSdk = await setupSdk(SDK_KEY); const poseStack = []; mpSdk.Camera.pose.subscribe((pose) => { poseStack.push({ ...pose, position: { ...pose.position }, projection: [...pose.projection], rotation: { ...pose.rotation }, sweep: pose.sweep.slice(), }); console.log(poseStack.length); }); }; main().catch((err) => console.error('Error:', err));
サブスクライブされる毎にposeStack
に状態が保持されています。
参考
以上